﻿using GN.Pay.Utils;
using GN.Pay.Utils.Reflection;
using GN.Pay.Utils.Reflection.Meta;
using GN.Pay.Utils.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.TradeChannel.WeiXin.Response
{
    /// <summary>
    /// 响应抽象
    /// </summary>
    [Serializable]
    public abstract class AResponse : AService
    {

        protected readonly string xmlMessage;

        /// <summary>
        /// 实例化 AResponse
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="config"></param>
        protected AResponse(string xml)
        {
            this.xmlMessage = xml;
            LoadXml(xml);
        }

        /// <summary>
        /// 签名键
        /// </summary>
        public static string sign_Key = "sign";

        /// <summary>
        /// 交易状态
        /// </summary>
        public string Trade_State { get; set; }

        /// <summary>
        /// 签名类型
        /// </summary>
        public string Sign_Type { get; set; }

        /// <summary>
        /// 返回代码
        /// </summary>
        public string Return_Code { get; set; }

        /// <summary>
        /// 返回消息
        /// </summary>
        public string Return_Msg { get; set; }

        /// <summary>
        /// 返回代码
        /// </summary>
        public string Result_Code { get; set; }

        /// <summary>
        /// 错误代码
        /// </summary>
        public string Err_Code { get; set; }

        /// <summary>
        /// 错误详情
        /// </summary>
        public string Err_Code_Des { get; set; }

        /// <summary>
        /// 签名
        /// </summary>
        public string Sign { get; set; }

        /// <summary>
        /// 随机字符
        /// </summary>
        public string Nonce_Str { get; set; }

        /// <summary>
        /// 是否返回成功
        /// </summary>
        /// <returns></returns>
        public bool IsReturnSuccess()
        {
            return string.Compare(Return_Code, "SUCCESS", true) == 0;
        }

        /// <summary>
        /// 是否结果成功
        /// </summary>
        /// <returns></returns>
        public bool IsResultSuccess()
        {
            return string.Compare(Result_Code, "SUCCESS", true) == 0;
        }

        protected DateTime FormatTime(string time, string format)
        {
            if (string.IsNullOrWhiteSpace(time))
            {
                return DateTime.Now;
            }
            return DateTimeUtils.GetDateTimeFormat(time, format);
        }

        /// <summary>
        /// 是否全部成功
        /// </summary>
        /// <returns></returns>
        public bool IsFullSuccess()
        {
            return IsReturnSuccess() && IsResultSuccess();
        }


        /// <summary>
        /// 是否验签正确
        /// </summary>
        public bool SignVerify(WeiXinConfigure config)
        {
            var dic = WeiXinUtils.ToXmlDictionary(this.xmlMessage);
            dic.Remove(sign_Key);
            string content = dic.UrlLinkString(k =>
            {
                return k.ToLower();
            }, null) + "&key=" + config.ConfigureInfo.Key;
            var sign = Md5Utils.Sign(content, config.Encoding).ToUpperInvariant();
            return sign.Equals(Sign);
        }

        /// <summary>
        /// 加载
        /// </summary>
        /// <typeparam name="TValue">字典</typeparam>
        /// <param name="dic"></param>
        private void Load<TValue>(IDictionary<string, TValue> dic)
        {
            var ps = MetaPropertys();
            foreach (var p in ps)
            {
                TValue value;
                if (p.PropertyInfo.CanWrite && dic.TryGetValue(p.PropertyInfo.Name, out value) && value != null)
                {
                    p.SetMemberValue(this, DataConvertUtils.TargetValueConvert(p.PropertyInfo.PropertyType, value));
                }
            }
        }

        /// <summary>
        /// 加载Xml
        /// </summary>
        /// <param name="xml">xml</param>
        private void LoadXml(string xml)
        {
            var dic = WeiXinUtils.ToXmlDictionary(xml);
            Load(dic);           
        }
    }
}
